package org.jeecg.modules.wms.wmstask.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.bouncycastle.util.Strings;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.wms.config.WarehouseDictEnum;
import org.jeecg.modules.wms.inorder.entity.WmsStockInOrderItems;
import org.jeecg.modules.wms.inorder.entity.WmsStockInOrders;
import org.jeecg.modules.wms.inorder.service.IWmsStockInOrderItemsService;
import org.jeecg.modules.wms.inorder.service.IWmsStockInOrdersService;
import org.jeecg.modules.wms.inventory.service.IWmsInventoryTransService;
import org.jeecg.modules.wms.inventory.vo.WmsInventoryTransParam;
import org.jeecg.modules.wms.warehouse.entity.WmsStorageLocations;
import org.jeecg.modules.wms.warehouse.service.IWmsStorageLocationsService;
import org.jeecg.modules.wms.wmstask.entity.WmsTasks;
import org.jeecg.modules.wms.wmstask.entity.WmsTasksRecords;
import org.jeecg.modules.wms.wmstask.mapper.WmsTasksMapper;
import org.jeecg.modules.wms.wmstask.service.IWmsTasksRecordsService;
import org.jeecg.modules.wms.wmstask.service.IWmsTasksService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 任务表
 * @Author: jeecg-boot
 * @Date: 2025-10-28
 * @Version: V1.0
 */
@Service
public class WmsTasksServiceImpl extends ServiceImpl<WmsTasksMapper, WmsTasks> implements IWmsTasksService {
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private IWmsStockInOrdersService wmsStockInOrdersService;
    @Autowired
    private IWmsStockInOrderItemsService wmsStockInOrderItemsService;
    @Autowired
    private WmsTasksMapper wmsTasksMapper;
    @Autowired
    private IWmsStorageLocationsService wmsStorageLocationsService;
    @Autowired
    private IWmsStockInOrdersService wmsStockInOrderService;
    @Autowired
    @Qualifier(value = "wmsInventoryTransByReceiving")
    private IWmsInventoryTransService wmsInventoryTransService;
    @Autowired
    private IWmsTasksService iWmsTasksService;

    /**
     * 收货任务执行
     *
     * @param param
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void receive(WmsTasksRecords param) {
        //执行任务
        WmsTasks execute = this.execute(param);
        //更新入库单明细
        this.wmsStockInOrderItemsService.updateStatus(param.getStockInOrderItemId());
        //更新入库单
        String status = this.wmsStockInOrderService.updateStatus(param.getStockInOrderId());

        //创建上架记录
        if (WarehouseDictEnum.INBOUND_RECEIVED.getCode().equals(status)) {
            this.createPutAwayTasks(execute);
        }
        //库存变更
        extracted(param, execute);
    }

    @Autowired
    private IWmsTasksRecordsService wmsTasksRecordsService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public WmsTasks execute(WmsTasksRecords param) {
        WmsTasks tasks = this.getById(param.getTaskId());
        Integer completedQuantity = ObjectUtil.defaultIfNull(tasks.getCompletedQuantity(), 0);
        Integer executedQuantity = ObjectUtil.defaultIfNull(param.getExecQuantity(), 0);
        Integer totalQuantity = ObjectUtil.defaultIfNull(tasks.getQuantity(), 0);
        if (completedQuantity + executedQuantity > totalQuantity) {
            throw new JeecgBootException("本次收货数量超出任务预收总量");
        }
        String inventoryAttribute = param.getInventoryAttribute();
        String locationCode = param.getTargetLocationCode();
        WmsStorageLocations wmsStorageLocations = wmsStorageLocationsService.getOne(Wrappers.lambdaQuery(WmsStorageLocations.class)
                .eq(WmsStorageLocations::getLocationCode, locationCode)
        );
        String isSellable = wmsStorageLocations.getIsSellable();
        if (!"1".equals(isSellable) && WarehouseDictEnum.INVENTORY_ATTRIBUTE_DEFECTIVE.getCode().equals(inventoryAttribute)) {
            throw new JeecgBootException("不良品不可售");
        }

        param.setProductId(tasks.getProductId());
        param.setOperator(tasks.getOperator());
        param.setOperationTime(new Date());
        param.setStockInOrderId(tasks.getStockInOrderId());
        param.setStockInOrderItemId(tasks.getStockInOrderItemId());

        try {
            wmsTasksRecordsService.save(param);
        } catch (Exception e) {
            throw new JeecgBootException("任务执行记录添加失败");
        }
        try {
            this.update(Wrappers.lambdaUpdate(WmsTasks.class)
                    .set(executedQuantity + completedQuantity <= totalQuantity, WmsTasks::getCompletedQuantity, completedQuantity + executedQuantity)
                    .set(WmsTasks::getTaskStatus,
                            ObjectUtil.equals(completedQuantity + executedQuantity, totalQuantity) ? WarehouseDictEnum.TASK_STATUS_COMPLETED.getCode()
                                    : WarehouseDictEnum.TASK_STATUS_EXECUTING.getCode())
                    .eq(WmsTasks::getId, tasks.getId())
            );
        } catch (Exception e) {
            throw new JeecgBootException("任务更新失败");
        }
        return tasks;
    }


    /**
     * 变更库存信息
     *
     * @param param
     * @param execute
     */
    private void extracted(WmsTasksRecords param, WmsTasks execute) {
        WmsInventoryTransParam inventoryParam = new WmsInventoryTransParam();
        inventoryParam.setIsSellable(
                WarehouseDictEnum.INVENTORY_ATTRIBUTE_GOOD.getCode().equals(param.getInventoryAttribute()) ? "1" : "0");
        inventoryParam.setProductId(execute.getProductId());
        inventoryParam.setTargetLocationCode(param.getTargetLocationCode());
        inventoryParam.setSourceLocationCode(param.getSourceLocationCode());
        inventoryParam.setExecQuantity(param.getExecQuantity());
        inventoryParam.setBatchNumber(param.getBatchNumber());
        //仓库id
        inventoryParam.setWarehouseId(param.getTargetWarehouseId());
        //保质期
        inventoryParam.setExpiryDate(param.getExpiryDate());
        //变更类型
        inventoryParam.setTransactionType(WarehouseDictEnum.INVENTORY_RECEIVING.getCode());
        //执行时间
        inventoryParam.setOperationTime(new Date());
        //执行人
        inventoryParam.setOperator(param.getOperator());
        try {
            wmsInventoryTransService.transInventory(inventoryParam);
        } catch (Exception e) {
            throw new JeecgBootException("库存变更失败");
        }
    }

    @Override
    public void createPutAwayTasks(WmsTasks execute) {
        //查询入库单信息
        WmsStockInOrders stockInOrders = wmsStockInOrdersService.getById(execute.getStockInOrderId());
        List<WmsStockInOrderItems> allRecords = wmsStockInOrderItemsService.list(Wrappers.lambdaQuery(WmsStockInOrderItems.class)
                .eq(WmsStockInOrderItems::getOrderId, stockInOrders.getId())
        );
        //根据入库单明细id分组,key是入库单明细id，value是WmsStockInOrderItems
        Map<String, WmsStockInOrderItems> recordsMap = allRecords.stream()
                .collect(Collectors.toMap(WmsStockInOrderItems::getId, item -> item));

        //遍历这个map，获取入库单明细信息集合list,其中把明细表中实际收货数量设置成采购数量-良品数量数量
        List<WmsStockInOrderItems> records = allRecords.stream()
                .peek(item ->
                        item.setReceivedQuantity(item.getExpectedQuantity() - item.getDefectiveQuantity())).toList();

        for (WmsStockInOrderItems item : records) {
            //创建上架任务,只创建实际收货数量不为0的明细
            if (item.getReceivedQuantity() > 0) {
                WmsTasks putAwayTask = new WmsTasks();
                BeanUtil.copyProperties(execute, putAwayTask);
                putAwayTask.setId(null);
                putAwayTask.setStockInOrderItemId(item.getId());
                putAwayTask.setCreateTime(new Date());
                putAwayTask.setUpdateTime(null);
                putAwayTask.setTaskNumber(this.generateInTaskNo());
                putAwayTask.setTaskStatus(WarehouseDictEnum.TASK_STATUS_CREATED.getCode());
                putAwayTask.setTaskType(WarehouseDictEnum.TASK_TYPE_PUTAWAY.getCode());
                putAwayTask.setProductId(item.getProductId());
                putAwayTask.setQuantity(item.getReceivedQuantity()); // 上架数量为良品数量
                //完成数量为0
                putAwayTask.setCompletedQuantity(0);
                //执行时间和完成时间都为空
                putAwayTask.setOperationTime(null);
                putAwayTask.setCompletedAt(null);
                try {
                    this.save(putAwayTask);
                } catch (Exception e) {
                    throw new JeecgBootException("保存任务失败");
                }
            }

        }
    }

    /**
     * 上架任务执行
     *
     * @param records
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void putAway(WmsTasksRecords records) {
        WmsTasks tasks = this.getById(records.getTaskId());
        String inOrderId = tasks.getStockInOrderId();
        String inOrderItemId = tasks.getStockInOrderItemId();
        WmsTasksRecords param = new WmsTasksRecords();
        BeanUtil.copyProperties(records, param);
        param.setStockInOrderId(inOrderId);
        param.setStockInOrderItemId(inOrderItemId);
        //执行任务
        WmsTasks execute = this.putAwayExecute(param);
        this.wmsStockInOrderItemsService.updateStatusPutAway(param.getStockInOrderItemId());
        //更新入库单

        String status = this.wmsStockInOrderService.updateStatusPutAway(param.getStockInOrderId());
        //TODO库存更改

    }

    @Override
    public WmsTasks putAwayExecute(WmsTasksRecords param) {
        WmsTasks tasks = this.getById(param.getTaskId());
        //先对执行数量进行校验，执行数量+已经完成数量不能大于总数量
        Integer completedQuantity = ObjectUtil.defaultIfNull(tasks.getCompletedQuantity(), 0);
        Integer executedQuantity = ObjectUtil.defaultIfNull(param.getExecQuantity(), 0);
        Integer totalQuantity = ObjectUtil.defaultIfNull(tasks.getQuantity(), 0);
        if (completedQuantity + executedQuantity > totalQuantity) {
            throw new JeecgBootException("本次上架数量超出任务预收总量");
        }

        param.setProductId(tasks.getProductId());
        param.setOperator(tasks.getOperator());
        param.setOperationTime(new Date());
        param.setStockInOrderId(tasks.getStockInOrderId());
        param.setStockInOrderItemId(param.getStockInOrderItemId());
        try {
            wmsTasksRecordsService.save(param);
        } catch (Exception e) {
            throw new JeecgBootException("任务执行记录添加失败");
        }

        try {
            this.update(Wrappers.lambdaUpdate(WmsTasks.class)
                    .set(executedQuantity + completedQuantity <= totalQuantity, WmsTasks::getCompletedQuantity, completedQuantity + executedQuantity)
                    .set(WmsTasks::getTaskStatus,
                            ObjectUtil.equals(completedQuantity + executedQuantity, totalQuantity) ? WarehouseDictEnum.TASK_STATUS_COMPLETED.getCode()
                                    : WarehouseDictEnum.TASK_STATUS_EXECUTING.getCode())
                    .eq(WmsTasks::getId, tasks.getId())
            );
        } catch (Exception e) {
            throw new JeecgBootException("任务更新失败");
        }
        return tasks;
    }


    /**
     * 基于收货单明细创建收货任务
     *
     * @param id       入库单id
     * @param operator 操作人的id<br>
     *                 stockInOrders 入库单信息<br>
     *                 itemsInOrders 入库单明细信息<br>
     *                 wmsTasks 创建的任务信息<br>
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void createReceiveTasks(String id, String operator) {
        //根据入库单id查询入库单状态信息
        WmsStockInOrders stockInOrders = wmsStockInOrdersService.getById(id);
        //审核通过才可以创建任务
        if (!stockInOrders.getStatus().equals(WarehouseDictEnum.INBOUND_APPROVED.getCode())) {
            throw new JeecgBootException("入库单审核通过才可以创建任务");
        }
        List<WmsStockInOrderItems> itemsInOrders = wmsStockInOrderItemsService.selectByMainId(id);
        if (CollUtil.isEmpty(itemsInOrders)) {
            throw new JeecgBootException("入库单没有明细信息，不可创建任务");
        }
        List<WmsTasks> wmsTasksList = this.createWmsTasks(id, operator, itemsInOrders, stockInOrders);
        this.saveBatch(wmsTasksList);
        //更新入库单表状态为收货中、更新入库单明细表中所有明细为收货中
        boolean isUpdate = wmsStockInOrdersService.update(Wrappers.lambdaUpdate(WmsStockInOrders.class)
                .eq(WmsStockInOrders::getId, id)
                .set(WmsStockInOrders::getStatus, WarehouseDictEnum.INBOUND_RECEIVING.getCode()));
        if (!isUpdate) {
            throw new JeecgBootException("更新入库单状态失败");
        }
        //把所有符合条件的入库单明细，更新为收货中
        boolean updated = wmsStockInOrderItemsService.update(Wrappers.lambdaUpdate(WmsStockInOrderItems.class)
                .eq(WmsStockInOrderItems::getOrderId, id)
                .set(WmsStockInOrderItems::getStatus, WarehouseDictEnum.INBOUND_DETAIL_RECEIVING.getCode()));
        if (!updated) {
            throw new JeecgBootException("更新入库单明细状态失败");
        }
    }
//============================================================
    /**
     * 创建收货任务
     *
     * @param id
     * @param operator
     * @param itemsInOrders
     * @param stockInOrders
     * @return
     */
    @NotNull
    private List<WmsTasks> createWmsTasks(String id, String operator,
                                          List<WmsStockInOrderItems> itemsInOrders, WmsStockInOrders stockInOrders) {
        List<WmsTasks> wmsTasksList = new ArrayList<>(itemsInOrders.size());
        //创建任务--》基于入库单明细
        for (WmsStockInOrderItems itemsInOrder : itemsInOrders) {
            //任务类型：收货，拣货，上架
            WmsTasks wmsTasks = new WmsTasks();
            wmsTasks.setTaskType(WarehouseDictEnum.TASK_TYPE_RECEIVING.getCode());
            //任务状态：已创建
            wmsTasks.setTaskStatus(WarehouseDictEnum.TASK_STATUS_CREATED.getCode());
            wmsTasks.setCreateTime(new Date());
            //任务号:
            wmsTasks.setTaskNumber(this.generateInTaskNo());
            //入库单和明细id
            wmsTasks.setStockInOrderId(id);
            wmsTasks.setStockInOrderItemId(itemsInOrder.getId());
            wmsTasks.setProductId(itemsInOrder.getProductId());
            //设置目的仓库
            wmsTasks.setTargetWarehouseId(stockInOrders.getWarehouseId());
            //商品采购数量
            wmsTasks.setQuantity(itemsInOrder.getExpectedQuantity());
            wmsTasks.setCompletedQuantity(0);
            wmsTasks.setOperator(operator);
            wmsTasksList.add(wmsTasks);
        }
        return wmsTasksList;
    }

    /**
     * 生成任务单号
     *
     * @return code
     */
    @Override
    public String generateInTaskNo() {
        String dateStr = DateUtils.now().substring(0, 10).replace("-", "");
        //redis自动生成序号
        long incr = 0;
        try {
            incr = redisUtil.incr("wms:asn_number" + dateStr, 1);
            if (incr == 1) {
                redisUtil.expire("wms:asn_number", 24 * 60 * 60 + 60);//加60秒，防止时间出现误差
            }
        } catch (Exception e) {
            throw new JeecgBootException("生成入库单号失败");
        }
        return "TSK" + dateStr + String.format("%05d", incr);
    }

    @Override
    public IPage<WmsTasks> pagePlus(Page<WmsTasks> page, WmsTasks wmsTasks) {
        return wmsTasksMapper.pagePlus(page, wmsTasks);
    }
}
